laetitia:~/tech/laetitia/adventofcode/SQL/2023/01|master⚡ ⇒ ll
total 120
drwxr-xr-x 7 laetitia staff 224 Dec 14 00:14 .
drwxr-xr-x 9 laetitia staff 288 Dec 7 07:55 ..
-rw-r--r-- 1 laetitia staff 41 Dec 1 06:18 example.csv
-rw-r--r-- 1 laetitia staff 21760 Dec 1 09:36 full.csv
-rw-r--r-- 1 laetitia staff 21760 Dec 1 12:35 input.csv
-rw-r--r-- 1 laetitia staff 2928 Dec 1 14:23 solution.sql
id integer
/* Use psql, the best Postgres client */
\copy input(data) from 'input.csv';
laetitia:~/tech/laetitia/adventofcode/SQL/2023/01 ⇒ cat example.csv
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
→ Can't rollback a single transaction
→ Create everything in a schema!
→ Drop the schema (Cascading)!
create index on production (minute, bluePrintId);
create index on map ((p[1]),(p[0]));
create index on map using gist (p) where value='#';
psql
psql
laetitia=# \h create function
Command: CREATE FUNCTION
Description: define a new function
Syntax:
CREATE [ OR REPLACE ] FUNCTION
name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )
[ RETURNS rettype
| RETURNS TABLE ( column_name column_type [, ...] ) ]
{ LANGUAGE lang_name
| TRANSFORM { FOR TYPE type_name } [, ... ]
| WINDOW
| { IMMUTABLE | STABLE | VOLATILE }
| [ NOT ] LEAKPROOF
| { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }
| { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }
| PARALLEL { UNSAFE | RESTRICTED | SAFE }
| COST execution_cost
| ROWS result_rows
| SUPPORT support_function
| SET configuration_parameter { TO value | = value | FROM CURRENT }
| AS 'definition'
| AS 'obj_file', 'link_symbol'
| sql_body
} ...
URL: https://www.postgresql.org/docs/devel/sql-createfunction.html
psql
laetitia=# \df regexp_substr
List of functions
Schema | Name | Result data type | Argument data types | Type
------------+---------------+------------------+---------------------------------------------+------
pg_catalog | regexp_substr | text | text, text | func
pg_catalog | regexp_substr | text | text, text, integer | func
pg_catalog | regexp_substr | text | text, text, integer, integer | func
pg_catalog | regexp_substr | text | text, text, integer, integer, text | func
pg_catalog | regexp_substr | text | text, text, integer, integer, text, integer | func
(5 rows)
generate_series
generate_series
select x.*, y.*
from generate_series(minx, maxx) as x(n),
generate_series(miny, maxy) as y(n)
generate_series
with ordinality
if neededselect int8range(numbers[odd.n]::bigint,
numbers[odd.n]::bigint + numbers[even.n]::bigint)
from (select * from input where id=1),
/* cross join but as we have only one row with id=1, we should be ok */
generate_series(1,20,2) with ordinality as odd(n,id)
inner join generate_series(2,20,2) with ordinality as even(n,id)
on odd.id = even.id
where numbers[odd.n] is not null
and numbers[even.n] is not null
generated columns
create table input (
id integer generated always as identity);
generated columns
create table input (
id integer generated always as identity,
value text);
insert into input(id,value)
overriding system value
(select generate_series(0,-1*(rows*9),-1),
']'
from (select count(*) from input where cat = 'crates') as t(rows))
;
generated columns
create table input (
id integer generated always as identity primary key,
data text not null,
hand text generated always as
((regexp_split_to_array(data, ' '))[1]) stored,
bet int generated always as
((regexp_split_to_array(data, ' '))[2]::int) stored,
A int generated always as (regexp_count(data,'A')) stored,
K int generated always as (regexp_count(data,'K')) stored,
Q int generated always as (regexp_count(data,'Q')) stored,
J int generated always as (regexp_count(data,'J')) stored,
nine int generated always as (regexp_count(data,'9')) stored,
eight int generated always as (regexp_count(data,'8')) stored,
seven int generated always as (regexp_count(data,'7')) stored,
six int generated always as (regexp_count(data,'6')) stored,
five int generated always as (regexp_count(data,'5')) stored,
four int generated always as (regexp_count(data,'4')) stored,
three int generated always as (regexp_count(data,'3')) stored,
two int generated always as (regexp_count(data,'2')) stored
)
regexp_matches(value, '[a-zA-Z]{4}','g')
regexp_count(data,'K')
filter
clausefilter
used with count
is
particularfilter
clausecount(*) filter (where <condition>)
count(case when <condition> then 1 end)
select
count(*) as unfiltered,
count(*) filter (where i < 5) AS filtered
FROM generate_series(1,10) AS s(i);
unfiltered | filtered
------------+----------
10 | 4
(1 row)
filter
clauseselect sum(value) as first_star
from (
select value,
count(*) filter (where value is null)
over (order by id) as grp
from input
)
group by grp
order by first_star desc
fetch first row only
;
1 subquery and 8 lines of code instead of 4 CTEs and 63 lines of code
as
keyword/* get the lastId of the range + the range number (also known as eflNumber) */
with lastId(id, elfNumber) as (...),
/* get the firstId of the range + the range number (also known as eflNumber) */
firstId(id, elfNumber) as (...),
/* get the elfNumber for each value */
elfNumbers(id, elfNumber) as (...),
/* get the total calories for each elf */
totalCalories(value) as (...)
select max(value) as PartOne
from totalCalories;
with recursive t(n) as (
values (1)
union all
select n+1
from t
where n < 100
)
select sum(n) from t;
\gexec
create table (n interger);
create procedure demonstration(myn integer) as
$demonstration$
update demo set n= myn + 1;
$demonstration$ language sql;
\gexec
select $$call demonstration($$ || n || $$);$$
from generate_series(1,100) t(n)
\gexec
\set QUIET on
\set QUIET on
select $$call demonstration($$ || n || $$);$$
from generate_series(1,100) t(n)
\gexec
\set QUIET off
create table demo (n integer);
create procedure increment(myn integer) as
$increment$
update demo set n= myn + 1
$increment$ language sql;
\set QUIET on
select $$call demonstration($$ || n || $$);$$
from generate_series(1,100) t(n)
\gexec
\set QUIET off
select sum(n)
from demo;
nullif
nullif
update input
set
elf = nullif(substring(value from 2 for 1),' ');
/* Let's create a map.
* The cave is 7 units wide. The floor is the 7 points with height 0).
* We'll also add 5 free lines.
* Thanks to my dad pointing that out, as the rocks first moves
* right/left and then down, we have to code the last movement
* differently. This is not very smart. My dad suggested that we
* instead make the rock appear on the 5th line after the highest
* rock which should make all moves behave the same way (and is
* possible because the rock will always be able to go down on the
* first move.
*/